﻿using Castle.Components.DictionaryAdapter.Xml;

using Microsoft.Extensions.Logging;

using PLCS.Domain.Equipments;
using PLCS.Domain.Shared.Enums;
using PLCS.Domain.Shared.Tasks;
using PLCS.Domain.Stations;
using PLCS.Domain.Tasks;
using PLCS.Domain.Trays;
using PLCS.EntityFrameworkCore.Tasks;
using PLCS.Shared.Common.Constant;

using Volo.Abp.Domain.Repositories;

namespace PLCS.Web.EventHandlers.TaskFinshed
{
    public class InstructionFinshEventHandler : ILocalEventHandler<InstructionFinshEvent>, ITransientDependency
    {
        private readonly ITaskRepository _taskRepository;
        private readonly IRepository<HisInstruction, Guid> _hisInstructionRepository;
        private readonly IStationRepository _stationRepository;
        private readonly IEquipmentRepository _equipmentRepository;
        private readonly IRepository<Tray, Guid> _trayRepository;
        private readonly ILogger<InstructionFinshEventHandler> _logger;
        private readonly IInstructionRepository _instructionRepository;

        public InstructionFinshEventHandler(ITaskRepository taskRepository,
                                            IRepository<HisInstruction, Guid> hisInstructionRepository,
                                            IStationRepository stationRepository,
                                            IEquipmentRepository equipmentRepository,
                                            IRepository<Tray, Guid> trayRepository,
                                            ILogger<InstructionFinshEventHandler> logger,
                                            IInstructionRepository instructionRepository)
        {
            _taskRepository = taskRepository;
            this._hisInstructionRepository = hisInstructionRepository;
            _stationRepository = stationRepository;
            _equipmentRepository = equipmentRepository;
            _trayRepository = trayRepository;
            _logger = logger;
            _instructionRepository = instructionRepository;
        }

        public async Task HandleEventAsync(InstructionFinshEvent eventData)
        {
            try
            {
                await _instructionRepository.DeleteAsync(eventData.Id);
                var hisInstruction = new HisInstruction(eventData.InstructionNo,
                                                        eventData.EquipmentNo,
                                                        eventData.InstructionType,
                                                        eventData.StartPos,
                                                        eventData.EndPos,
                                                        eventData.TrayType,
                                                        eventData.MovePos);
                await _hisInstructionRepository.InsertAsync(hisInstruction);
                _logger.LogInformation($"指令'{eventData.InstructionNo}'已完成，将指令删除");

                if (eventData.TaskId == null)
                    return;
                Guid Id = (Guid)eventData.TaskId;
                var task = await _taskRepository.GetAsync(Id);
                Station? start = null;
                if (!string.IsNullOrWhiteSpace(eventData.StartPos))
                    start = await _stationRepository.GetStationByNumAsync(eventData.StartPos);
                Station? end = null;
                if (!string.IsNullOrWhiteSpace(eventData.EndPos))
                    end = await _stationRepository.GetStationByNumAsync(eventData.EndPos);
                Station? contain = null;
                if (!string.IsNullOrWhiteSpace(eventData.ContainStationNo))
                    contain = await _stationRepository.GetStationByNumAsync(eventData.ContainStationNo);
                if (task != null)
                {
                    switch (eventData.InstructionType)
                    {
                        case InstructionType.单取货:
                            if (start == null || contain == null) break;
                            await UpdateTrayDataAsync(start, contain);
                            break;

                        case InstructionType.单放货:
                            if (contain == null || end == null) break;
                            await UpdateTrayDataAsync(contain, end);
                            break;

                        case InstructionType.取放货:
                            if (start == null || end == null) break;
                            await UpdateTrayDataAsync(start, end);
                            break;

                        default:
                            break;
                    }

                    int index = GetIndexFromInstructionNo(eventData.InstructionNo);
                    if (index == -1)
                        return;

                    var maxIndex = GetIndexFromInstructionNo(task.Instructions.Select(x => x.InstructionNo).Max());

                    if (index == maxIndex)
                    {
                        task.ChangeStatus(Domain.Shared.Tasks.TaskStatus.已完成);
                        await _taskRepository.UpdateAsync(task);
                        _logger.LogInformation($"已完成最后一条指令，将任务'{task.TaskId}'置为已完成");
                    }
                }

                #region 执行完成之后，解锁工位

                var equipment = await _equipmentRepository.GetByEquipmentNoAsync(eventData.EquipmentNo);

                int maxTaskPosition = int.MaxValue;
                int minTaskPosition = int.MinValue;
                if (end == null && start != null && start.Position != 0)
                {
                    maxTaskPosition = Math.Max(start.Position, eventData.InitalPos);
                    minTaskPosition = Math.Min(start.Position, eventData.InitalPos);
                }
                else if (start == null && end != null && end.Position != 0)
                {
                    maxTaskPosition = Math.Max(end.Position, eventData.InitalPos);
                    minTaskPosition = Math.Min(end.Position, eventData.InitalPos);
                }
                else if (start != null && end != null && end.Position != 0 && start.Position != 0)
                {
                    maxTaskPosition = Math.Max(start.Position, end.Position); // 起始位和目标位的最大值
                    minTaskPosition = Math.Min(start.Position, end.Position); // 起始位和目标位的最小值
                }
                else if (eventData.InstructionType == InstructionType.单坐标行走)
                {
                    maxTaskPosition = Math.Max(eventData.MovePos, equipment.CurrentPos);
                    minTaskPosition = Math.Min(eventData.MovePos, equipment.CurrentPos);
                }
                else
                    return;

                if (equipment.CurrentPos < minTaskPosition)
                    minTaskPosition = equipment.CurrentPos;
                if (equipment.CurrentPos > maxTaskPosition)
                    maxTaskPosition = equipment.CurrentPos;
                var needLockStations = await _stationRepository.GetIntermediatePositions(minTaskPosition - LocalConfigManager.SafeDistance, minTaskPosition + LocalConfigManager.SafeDistance);
                foreach (Station item in needLockStations)
                {
                    item.IsLocked = YesNo.是;
                }
                await _stationRepository.UpdateManyAsync(needLockStations);

                #endregion 执行完成之后，解锁工位
            }
            catch (Exception ex)
            {
                _logger.LogError($"指令号'{eventData.InstructionNo}'任务更新失败，失败原因：{ex.Message}");
            }
        }

        private async Task UpdateTrayDataAsync(Station start, Station end)
        {
            if (start.Trays != null && start.Trays.Any())
            {
                try
                {
                    var tray = start.RemoveTray();
                    end.AddTray(tray);
                    _logger.LogInformation($"托盘数据更新成功，起始位：{start.StaNum},目标位：{end.StaNum},托盘编码：{tray.TrayNo}");
                }
                catch (Exception ex)
                {
                    _logger.LogError($"托盘数据更新失败,起始位：{start.StaNum},目标位：{end.StaNum},失败原因：{ex.Message}");
                }
            }

            #region 无光电货位

            if (start.StationType == Domain.Shared.Stations.StationType.无光电货位)
            {
                // 无光电货位，只能自己记有货无货
                start.ChangeHaveStatus(Domain.Shared.Enums.YesNo.否);
            }
            if (end.StationType == Domain.Shared.Stations.StationType.无光电货位)
            {
                // 无光电货位，只能自己记有货无货
                end.ChangeHaveStatus(Domain.Shared.Enums.YesNo.是);
            }

            #endregion 无光电货位

            await _stationRepository.UpdateManyAsync(new List<Station> { start, end });
        }

        private int GetIndexFromInstructionNo(int instructionNo)
        {
            // 将指令号转换为字符串
            string s = instructionNo.ToString();

            // 检查字符串长度是否为 9 位数
            if (s.Length != 9)
            {
                return -1; // -1说明不是9位数，也就是说这不是任务拆解出来的指令
            }

            // 获取 taskId 和 index 的字符串表示
            string taskIdStr = s.Substring(0, 4);
            string indexStr = s.Substring(4, 5).TrimEnd('0');

            // 转换 taskId 和 index 字符串为 int 类型，并计算 index 的值
            int taskId = int.Parse(taskIdStr);
            int index = int.Parse(indexStr);

            return index;
        }
    }
}